#include <iostream>
#include <string>
#include <fstream>
#include <iostream>
#include <limits>
#include <string>
#include <cstdio>
#include <boost/program_options.hpp>
#include <boost/filesystem/path.hpp>
#include "get_arg.h"


// link with -lboost_filesystem-gcc -lboost_program_options-gcc
// program_options_helper.cpp



// my functions
#define DEBUG_LEVEL 6
#include <debug_func.h>
#include <print_error.h>
#include <program_options_helper.h>

using std::ofstream;
using std::ifstream;
using std::cout;
using std::string;
using std::vector;
using std::cerr;
using namespace program_options_helper;
namespace po = boost::program_options_lg;


//_______________________________________________________________________________________

//		process_command_line_options

//				from command line
//				Created [9/13/2001]

//_______________________________________________________________________________________



bool process_command_line_options(int argc, char* argv[], t_program_args& args)
{
	//
	//	Mandatory arguments
	//
	//po::options_description mandatory_args("Mandatory Arguments");
	//mandatory_args.add_options()


	//
	//	Positional arguments
	//
	//po::positional_options_description positional_parser;
	//positional_parser.add("input_files", -1);
    //
	//po::options_description positional_args("Positional Arguments");
	//positional_args.add_options()
	//("input_files,i",	po::value<vector<string> >(&args.input_files)
	//										->set_name("FILES"),
	//										"dnds results.");

	//
	//	Optional arguments
	//
	args.optional_args.add_options()
	("input_file,i",		po::value<string>(&args.file_input)
										->set_name("FILE")
										->default_value("STDIN"),
									"File containing alignment results.")
	("output_ds_coverage,C",po::bool_switch(&args.output_ds_coverage),
									"Prints out seq identifiers and ds in "
									"tab-delimited columns.\n"
									"The fourth column contains 0 if "
									"--coverage_residues is met, "
									"or 1 or 2 to indicate the longer sequence if only "
									"--coverage_fragment is exceeded.")
	("output_ds_only,S",	po::bool_switch(&args.output_ds_only),
									"Only print out seq identifiers and ds in "
									"tab-delimited columns.\n"
									"Otherwise the entirety of each dnds "
									"result line is printed.")
	("output_dn_only,N",	po::bool_switch(&args.output_dn_only),
									"Only print out seq identifiers and dN in "
									"tab-delimited columns.\n"
									"Otherwise the entirety of each dnds "
									"result line is printed.")
	("results_summary,R",	po::value<string>(&args.results_summary)
											->set_name("FILE"),
									"Write out summary of relationship pairs greater than "
							  		"the set thresholds.")
	("ds_threshold,s",		po::value<float>(&args.ds_threshold)
											->set_name("NUMBER")
											->default_value(5.0),
									"Ignore results with Ks > NUMBER.\n"
									"NUMBER = 0 means do not filter.")
	("dn_threshold,n", 		po::value<float>(&args.dn_threshold)
											->set_name("NUMBER")
											->default_value(5.0),
									"Ignore results with Ks > NUMBER.\n"
									"NUMBER = 0 means do not filter.")
	("tau_threshold,t", 	po::value<float>(&args.tau_threshold)
											->set_name("NUMBER")
											->default_value(10.0),
									"Ignore results with Ks > NUMBER.\n"
									"NUMBER = 0 means do not filter.")
	("len_threshold,l",		po::value<unsigned>(&args.len_threshold)
											->set_name("NUMBER")
											->default_value(50),
									"Ignore results with number of aligned residues < "
									"NUMBER.\n"
									"NUMBER = 0 means do not filter.")
	("coverage_residues,r",	po::value<float>(&args.residues_coverage)
										->set_name("FRACTION")
										->default_value(0.75),
									"Ignore results where aligned residues covers less "
									"this fraction of residues in the LONGER sequence.\n"
									"(I.e. Fragments are discarde.)")
	("coverage_fragment,f",	po::value<float>(&args.fragment_coverage)
										->set_name("FRACTION")
											->default_value(0.75),
									"Ignore results where aligned residues covers less "
									"this fraction of residues in the SHORTER sequence.\n"
									"(I.e. Fragments are kept.)")
	("coverage_both,b",		po::bool_switch(&args.coverage_both),
									"Both coverage requirements have"
									"need to be satisfied at the same time for any "
									"sequence.)")
	("#comment,#",			po::value<string>(&args.comment_letters)
										->set_name("LETTERS")
										->default_value("#"),
									"Use one of these letters to begin a "
									"commented line.");
	args.add_std_options();

	//	Parse all arguments
	//
	po::options_description all_args("");
	all_args

				//	Mandatory arguments
				//.add(mandatory_args)

				//	Optional arguments
				.add(args.optional_args);

				//	Positional arguments
				//.add(positional_args);

	po::variables_map vm;
	po::store(po::command_line_parser(argc, argv)
								.options(all_args)

								//	Positional arguments
								// .positional(positional_parser)

								.run(), vm);
	po::notify(vm);


	if (vm.count("version"))
	{
		print_version(cerr, *argv, "1.5\n"
			"\tHistory: \n\n"
			"\tv 1.0\1"
			"04-01-2005\1"
			"Filter dNdS results which are beyond reasonable thresholds.\1"
			"Also can print out dS results in a tab-limited columns for use in "
			"building phylogenetic trees etc..\n"
			"\tv 1.1\1"
			"03-02-2005\1"
			"Bug fix. Cutoff of length = zero now kept \1"
			"(previously zero = max_uint)."
			"\tv 1.2\1"
			"05-08-2005\1"
			"Allow filtering on BOTH or EITHER coverage of shorter or longer sequence.\n"
			"\tv1.3\1"
			"23-08-2005\1"
			"Use single input file.\n"
			"\tv 1.4\1"
			"04-01-2006\1"
			"For Andreas: Hash start comment lines. Fix bugs in handling input. "
			"Upgrade to common code for sequence pair identifiers\n"
			"\tv 1.5\1"
			"27-03-2006\1"
			"Comments can begin with user-defined letters. Defaults to hash '#'\n"
			"22-05-2007\1"
			"Added --output_ds_coverage option."
					  
			);
		return false;
	}

	if (vm.count("help"))
	{
		string exe_description =
							"Takes a dnds result FILE produced by seq_pairs_kaks, "
							"screens for those which are greater than the specified "
							"thresholds.\n"
							"The output is sent to STDOUT\n"
							"Set any threshold to zero "
							" to avoid filtering on that parameters.\n"
							"Defaults to --coverage_residues 0.6 --coverage_fragment 0.75 "
							"meaning that sequences can align EITHER over 60% or more of the "
							"longer sequence or 75% or more of the shorter sequence.\n"
							"If '--coverage_both' is specified, the alignment of each "
							"sequence pair has to meet BOTH coverage thresholds.\n";

		//
		//	Only output visible arguments for help string
		//
		po::options_description visible_args("");
		visible_args

					//	Mandatory arguments
					//.add(mandatory_args)

					//	Optional arguments
					.add(args.optional_args);


		print_usage(cerr, string(*argv),    "[OPTIONS] FILES ",
							visible_args, exe_description, 80);
		return false;
	}

	// test for > threshold so everything will pass
	//check_required_options(vm, mandatory_args); 
	unsigned output_options = 0;
	 
	if (args.output_ds_only)
		++output_options;
	if (args.output_dn_only)
		++output_options;
	if (args.output_ds_coverage)
		++output_options;
	if (output_options > 1)
	{
		throw std::runtime_error("Please select only one out of --output_ds_coverage, "
								 "--output_ds_only or --output_dn_only.\n");
	}


	if (args.dn_threshold == 0.0)
		args.dn_threshold = std::numeric_limits<float>::max();
	if (args.tau_threshold == 0.0)
		args.tau_threshold = std::numeric_limits<float>::max();
	if (args.ds_threshold == 0.0)
		args.ds_threshold = std::numeric_limits<float>::max();
	if (args.fragment_coverage == 0.0 ||
		args.residues_coverage == 0.0)
		args.coverage_both = true;



	args.open_err_log();
	return true;
}




